package com.sky.interceptor;

import com.sky.constant.JwtClaimsConstant;
import com.sky.context.BaseContext;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            // 当前拦截到的不是动态方法，直接放行
            return true;
        }

        // 1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        // 记录当前服务器时间
        long currentTimeMillis = System.currentTimeMillis();
        log.info("服务器当前时间: {}", new Date(currentTimeMillis));
        log.info("配置的JWT有效期: {}毫秒", jwtProperties.getAdminTtl());

        // 检查令牌是否存在
        if (token == null || token.isEmpty()) {
            log.error("JWT令牌缺失: 请求头中未找到令牌");
            response.setStatus(401);
            return false;
        }

        // 2、校验令牌
        try {
            log.info("开始JWT校验: {}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());

            // 获取令牌中的时间信息
            Date issuedAt = claims.getIssuedAt();
            Date expiration = claims.getExpiration();

            // 记录时间信息（防御性处理）
            log.info("令牌签发时间: {}", issuedAt != null ? issuedAt : "未设置");
            log.info("令牌过期时间: {}", expiration);

            if (issuedAt != null && expiration != null) {
                log.info("令牌有效期: {}毫秒", expiration.getTime() - issuedAt.getTime());
                log.info("当前时间与令牌签发时间差: {}毫秒", currentTimeMillis - issuedAt.getTime());
            }
            log.info("当前时间与令牌过期时间差: {}毫秒", currentTimeMillis - expiration.getTime());

            // 设置当前登录用户id,存储到当前线程
            BaseContext.setCurrentId(empId);
            log.info("当前员工id：{}", empId);

            // 3、通过，放行
            return true;
        } catch (ExpiredJwtException ex) {
            // 获取令牌中的时间信息
            Claims claims = ex.getClaims();
            Date expiration = claims.getExpiration();
            Date issuedAt = claims.getIssuedAt(); // 可能为null

            log.error("JWT已过期: {}", ex.getMessage());

            // 防御性处理签发时间为null的情况
            if (issuedAt != null) {
                log.error("令牌签发时间: {}", issuedAt);
                log.error("令牌有效期: {}毫秒", expiration.getTime() - issuedAt.getTime());
                log.error("当前时间与令牌签发时间差: {}毫秒", currentTimeMillis - issuedAt.getTime());
            } else {
                log.error("令牌签发时间: 未设置");
            }

            log.error("令牌过期时间: {}", expiration);
            log.error("当前时间与令牌过期时间差: {}毫秒", currentTimeMillis - expiration.getTime());

            response.setStatus(401);
            return false;
        } catch (SignatureException ex) {
            log.error("JWT签名不匹配: 请检查密钥是否一致");
            response.setStatus(401);
            return false;
        } catch (MalformedJwtException ex) {
            log.error("JWT格式错误: {}", token);
            response.setStatus(401);
            return false;
        } catch (UnsupportedJwtException ex) {
            log.error("不支持的JWT类型: {}", token);
            response.setStatus(401);
            return false;
        } catch (IllegalArgumentException ex) {
            log.error("JWT参数错误: {}", ex.getMessage());
            response.setStatus(401);
            return false;
        } catch (Exception ex) {
            log.error("JWT解析异常: ", ex); // 打印完整堆栈
            response.setStatus(401);
            return false;
        }
    }
}